/*
	D3D11Client for Orbiter. 2011.
*/
#ifndef _RES_H
#define _RES_H

//#define DEBUG
#define _CRT_SECURE_NO_DEPRECATE

#include "..\include\OrbiterAPI.h"
#include "..\include\GraphicsAPI.h"
#include "..\include\Orbitersdk.h"
#include <physicalmonitorenumerationapi.h>

#include "include\libpng\png.h"
#include "include\libpng\pngstruct.h"

#include <d3d11.h>
#include <D3DX11tex.h>
#include <DxErr.h>
#include <D3Dcompiler.h>
#include <d3dx9math.h>
#include <vector>
#include <queue>
#include <memory>
#include <DXGI.h>
#include <ddraw.h>
#include <CommCtrl.h>
#include "CComPtrEx.h"

//====================================================================
//						(#define)s
//====================================================================

typedef struct DDS_HEADER {
	DWORD           dwSize;
	DWORD           dwFlags;
	DWORD           dwHeight;
	DWORD           dwWidth;
	DWORD           dwPitchOrLinearSize;
	DWORD           dwDepth;
	DWORD           dwMipMapCount;
	DWORD           dwReserved1[11];
	struct DDS_PIXELFORMAT {
		DWORD dwSize;
		DWORD dwFlags;
		DWORD dwFourCC;
		DWORD dwRGBBitCount;
		DWORD dwRBitMask;
		DWORD dwGBitMask;
		DWORD dwBBitMask;
		DWORD dwABitMask;
	} ddspf;
	DWORD           dwCaps;
	DWORD           dwCaps2;
	DWORD           dwCaps3;
	DWORD           dwCaps4;
	DWORD           dwReserved2;
} DDS_HEADER;

//#define DEBUG
#define LOG0 1		//always.
#define LOG1 1		//main functions.
#define LOG2 1		//causes perfomance drop.

#define IDS_INFO		1000
#define IDS_TYPE		1001
#define IDS_STRING1		1

#define VID_DEVICE		1019
#define VID_FULL		1020
#define VID_WINDOW		1021
#define VID_STATIC5		1022//?
#define VID_STATIC6		1023//?
#define VID_MODE		1024
#define VID_BPP			1025
#define VID_VSYNC		1026
#define VID_PAGEFLIP	1027
#define VID_STATIC7		1028
#define VID_STATIC8		1029
#define VID_STATIC9		1030
#define VID_WIDTH		1031
#define VID_HEIGHT		1032
#define VID_ASPECT		1033
#define VID_4X3			1034
#define VID_16X10		1035
#define VID_16X9		1036
#define VID_ENUM		1037
#define VID_D3D11CONFIG	9038
#define VID_STENCIL		1188

#define CTRL_OK			9000
#define CTRL_CANCEL		9001
#define CTRL_ABOUT		9002

#define CTRL_GENERAL	9003
#define CTRL_VESSELS	9004
#define CTRL_PLANETS	9005

#define CTRL_G_THREADS		9101	//+9102
#define CTRL_G_THREADS_HELP	9113

#define CTRL_G_AA			9103	//+9104
#define CTRL_G_AA_HELP		9114

#define CTRL_G_SKPAD		9105	//+9106
#define CTRL_G_SKPAD_HELP	9115

#define CTRL_G_MFDTEX		9107	//+9108
#define CTRL_G_MFDTRF		9111	//+9112

#define CTRL_G_PP_EFFECTS	9121	//+9122

#define CTRL_G_CREATE_SYM	9131	

//9202
#define CTRL_V_MIPMAP		9201
#define CTRL_V_MIPMAP_HLP	9224

//9204
#define CTRL_V_TEXFILTER		9203
#define CTRL_V_TEXFILTER_HLP	9223

//9207
#define CTRL_V_NORM		9205
#define CTRL_V_NORM_HLP	9206

//9210
#define CTRL_V_BUMP		9208
#define CTRL_V_BUMP_HLP	9209

//9213
#define CTRL_V_SPEC		9211
#define CTRL_V_SPEC_HLP	9212

//9216
#define CTRL_V_EMIS		9214
#define CTRL_V_EMIS_HLP	9215

//9219
#define CTRL_V_PSLLIGHTS		9217
#define CTRL_V_PSLLIGHTS_HLP	9218

//9222
#define	CTRL_V_BASELLIGHTS		9220
#define CTRL_V_BASELLIGHTS_HLP	9221

//9227
#define CTRL_V_TILELLIGHTS		9225
#define CTRL_V_TILELLIGHTS_HLP	9226

#define CTRL_P_LMODE	9301	//+9302
#define CTRL_P_LFREQ	9303	//+9304
#define CTRL_P_TEXFILTER	9305	//+9306
#define CTRL_P_TEXFILTER_HLP 9306
#define CTRL_P_LLIGHTS	9307	//+9308

/*
#define ADV_THREADING	9102
#define ADV_DEVICE		9103
#define ADV_RTYPE		9104
#define ADV_FILTER		9105*/

#define SPEC_DEFAULT 0xFFFFFFFF
#define SPEC_INHERIT 0xFFFFFFFE

#define LABEL_DISTLIMIT 0.6
#define MAXPLANET 512
#define SURF_MAX_PATCHLEVEL 14

#define C2504 0	//used for debugging C2504 "base class is undefined" error

//====================================================================
//						Macros
//====================================================================

#if LOG0
	#ifndef WLOG0
	#define WLOG0( x ) {	\
		oapiWriteLog( x );	\
	}
	#endif
#else
	#ifndef WLOG0
	#define WLOG0( x )
	#endif
#endif

#if LOG1
	#ifndef WLOG1
	#define WLOG1( x ) {	\
		oapiWriteLog( x );	\
	}
	#endif
#else
	#ifndef WLOG1
	#define WLOG1( x )
	#endif
#endif

#if LOG2
	#ifndef WLOG2
	#define WLOG2( x ) {	\
		oapiWriteLog( x );	\
	}
	#endif
#else
	#ifndef WLOG2
	#define WLOG2( x )
	#endif
#endif

#if defined DEBUG
	#ifndef HR
	#define HR(x) {			\
		HRESULT hr = (x);	\
		if( FAILED(hr))	{	\
		DXTrace( __FILE__ , (DWORD) __LINE__, hr, #x, true );	} \
		}
	#endif
#else
	#ifndef HR
	#define HR(x) (x) 
	#endif
#endif

#define REL(x) {	if( (x) ) {	(x)->Release();	(x) = nullptr;	} }
#define HRFAIL( hr ) ( ((HRESULT)(hr)) < 0 )

#define SHOW_MESSAGE(cap,msg) MessageBoxA( 0, msg, cap, MB_ICONERROR | MB_OK )

#define CLAMP_VALUE(val,min,max) val = (val < min) ? min : (val > max)? max : val

//====================================================================
//						Global vars
//====================================================================
extern bool tRender;

extern IDXGIFactory1 *Factory;
extern IDXGISwapChain *SwapChain;

extern ID3D11Device *gd3dDevice;			//device
extern ID3D11DeviceContext *iCtx;	//immediate context
/*
extern ID3D11DeviceContext *dCtx0;	//deffered context #0
*/
extern ID3D11SamplerState
	*SS_Point_Wrap,
	*SS_Linear_Wrap,
	*SS_Linear_Clamp;

extern ID3D11Buffer
	*cb_D3DXMATRIX_x1,
	*cb_D3DXMATRIX_x2,
	*cb_D3DXVECTOR4;

extern ID3D11RasterizerState
	*RS_CullBack_Solid,
	*RS_CullBack_Wire,
	*RS_CullFront_Solid,
	*RS_CullFront_Wire,
	*RS_CullNone_Solid,
	*RS_CullNone_Wire;

extern ID3D11BlendState
	*BS_SrcAlpha,
	*BS_InvSrcAlpha,
	*BS_NoBlend;

extern ID3D11DepthStencilState
	*DSS_NoDepth_NoStencil,
	*DSS_TestDepthOnly_NoStencil;

extern UINT
	ShaderCompileFlag;

extern char
	vs_ver[32],
	gs_ver[32],
	ps_ver[32];

extern ID3D11Texture2D
	*Tex_2x2;

extern ID3D11RenderTargetView
	*RTV_Tex_2x2;

extern float fAmbient;	//global ambient level

//multithreading:
extern bool
	bRender,
	bBBRender;
extern HANDLE RenderThread;
extern HANDLE FrameReady;
extern HANDLE UpdateReady;
extern CRITICAL_SECTION Resources;

extern HANDLE ResourceRequest;	//"resource request was made" event
extern HANDLE ResourceReleased;	//event

inline void CheckResourceRequest();
void ProcessResourceRequest();




//====================================================================
//						Math functions
//====================================================================

HRESULT D3DMAT_MatrixInvert (D3DXMATRIX *res, D3DXMATRIX *a);
float D3DMAT_BSScaleFactor(const D3DXMATRIX *mat);
void D3DMAT_RotY( D3DXMATRIX *mat, double r );
void D3DMAT_FromAxisT( D3DXMATRIX *mat, const D3DVECTOR *x, const D3DVECTOR *y, const D3DVECTOR *z );
void D3DMAT_CreateX_Billboard( const D3DXVECTOR3 *toCam, const D3DXVECTOR3 *pos, float size, D3DXMATRIX *pOut );
void D3DMAT_CreateX_Billboard( const D3DXVECTOR3 *toCam, const D3DXVECTOR3 *pos, const D3DXVECTOR3 *dir, float size, float stretch, D3DXMATRIX *pOut );
void ShowShaderCompilationError( HRESULT hr, ID3DBlob *err );

//====================================================================
//						Type conversion functions
//====================================================================

struct PTVertex {
	float px, py;
	float tu, tv;
};

PTVertex _vPT( float px, float py, float tu, float tv );
D3DXCOLOR C4ToD4( COLOUR4 colour );
void V3toD3( D3DXVECTOR3 *out, VECTOR3 *in );
void M3ToDM( D3DXMATRIX *out, MATRIX3 *in );
short mod( short a, short b );
float saturate( float x );

typedef struct ATM_FOG_PARAMS {
	D3DXVECTOR4 SunDir;
	UINT32 HazeMode;
//legacy atmosphere
	float Ambient0;
	float GlobalAmb;
	float SunAppRad;
	float Dispersion;
//fog params	
	D3DXCOLOR FogColor;	
	float FogDensity;	
} ATM_FOG_PARAMS;

typedef struct Sun_spec {
	D3DXVECTOR4 SunDir;
	D3DXCOLOR ambient;
	D3DXCOLOR diffuse;
	D3DXCOLOR specular;	//64
} Sun_spec;

//====================================================================
//						Performance counter
//====================================================================

class PerformanceCounter {
public:
	PerformanceCounter();
	~PerformanceCounter();

	void Start();
	void End();
	void End( char *comment );

	char *GetLine();
	void ShowLine();
private:
	__int64		start;
	double freq;
	char line[64];
	char string[128];
};
extern PerformanceCounter *PCounter;

//====================================================================
//						D3D11Config
//====================================================================

/*
D3D11Config.cfg file:
D3D11ClientConfig Params,
DWORD NumAAModes,
AAConfig AAModes[NumAAModes];

No AA
MSAA x2
MSAA x4
MSAA x8
CSAA x8		CFAA x8
CSAA x8Q	CFAA x8Q
CSAA x16	CFAA x16
CSAA x16Q	CFAA x16Q

Not recognized 0
NVidia		4318
AMD/ATI		1022
Intel		8086 :)
*/
struct D3D11FileConfig {
	int
		Thread_mode,
		AA_count,
		AA_mode,
		Sketchpad_mode,
		MFD_filter,
		MFD_transparency,
		PP_effect_enable,

		Mesh_Texture_Mip_maps,
		Mesh_Texture_Filter,
		Mesh_Normal_maps,
		Mesh_Bump_maps,
		Mesh_Specular_maps,
		Mesh_Emissive_maps,
		Mesh_Base_LLights,
		Base_LLights,
		PStream_LLights,
		PlanetTile_LLights,

		Planet_Texture_filter,
		Planet_Tile_loading_Freq;
};

struct AA_MODE_DESC {
	char desc[16];
	DXGI_SAMPLE_DESC SDesc;
};

class D3D11Client;

class D3D11Config {
	friend class VideoTab;
public:
	D3D11Config(D3D11Client *pGC);
	~D3D11Config();

	void EnumerateAll( oapi::GraphicsClient::VIDEODATA *vdata );

	bool LoadConfig();
	void FindSupportedAAModes();
	void SetDefault();
	void UpdateConfig();
	void SaveConfig();
	void ApplyConfig();	

	IDXGIAdapter *Adapter;
	IDXGIOutput *Output;
	DXGI_MODE_DESC Mode;
	DXGI_SAMPLE_DESC CurrentAAMode;

	D3D_DRIVER_TYPE DriverType;
	D3D_FEATURE_LEVEL SucceededFL;

	DXGI_FORMAT RTFormat;

	int enablePPEffects;

	DWORD 
		Width,		//window full / fullscreen
		Height,		//window full / fullscreen
		cWidth,		//window active area
		cHeight,	//window active area
		SketchPadMode,
		TextureMipMapCount,
		TileLoadingFrequency,
		LF_MFDTexture;

	bool
		FullScreenWindow,		//full-screen mode
		NormalMaps,				//use normal maps
		BumpMaps,				//use bump maps
		SpecularMaps,			//use specular maps
		EmissiveMaps,			//use emissive maps
		bPreloadTiles;

	float
		Aspect,
		ShadowAlpha,
		MFDTransparency,
		BumpAmplitude;

	D3D11_FILTER
		FILTER_MeshTexture,		//vessel texture filtration
		FILTER_MeshNormalMap,
		FILTER_MeshSpecularMap,
		FILTER_MeshEmissiveMap,
		FILTER_PlanetTexture;

	DWORD 
		AF_FACTOR_MeshTexture,
		AF_FACTOR_MeshNormalMap,
		AF_FACTOR_MeshSpecularMap,
		AF_FACTOR_MeshEmissiveMap,
		AF_FACTOR_PlanetTexture;
	
private:
	D3D11_FILTER SetFilter( int value, DWORD &afactor );

	std::vector<char*> AdapterOutputDesc;
	std::vector<IDXGIAdapter1*> Adapters;
	std::vector<IDXGIOutput*> Outputs;
	UINT NumOutputs;
	DXGI_MODE_DESC *Modes;

	FILEHANDLE CfgFILE;
	D3D11FileConfig Cfg;
	AA_MODE_DESC *AAModes;
	D3D11Client *mGraphicsClient;
};

/*
class D3D11Stats {
public:
	D3D11Stats();
	~D3D11Stats();

	void Show();

	DWORD
		tcount,		//triangles
		gcount,		//groups
		mcount;		//meshes

private:
};

D3D11Stats *info;*/

HRESULT CompileFromFile(LPCSTR pSrcFile,CONST D3D10_SHADER_MACRO* pDefines, LPD3D10INCLUDE pInclude,
        LPCSTR pFunctionName, LPCSTR pProfile, UINT Flags1, UINT Flags2, ID3DX11ThreadPump* pPump, ID3D10Blob** ppShader, ID3D10Blob** ppErrorMsgs, HRESULT* pHResult);

bool CompileShaderFromFile( LPCSTR szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, const D3D10_SHADER_MACRO * defines = nullptr );

#pragma pack(push,1)
struct TILEFILESPEC {
	DWORD sidx;       // index for surface texture (-1: not present)
	DWORD midx;       // index for land-water mask texture (-1: not present)
	DWORD eidx;       // index for elevation data blocks (not used yet; always -1)
	DWORD flags;      // tile flags: bit 0: has diffuse component; bit 1: has specular component; bit 2: has city lights
	DWORD subidx[4];  // subtile indices
};

struct LMASKFILEHEADER {
	char id[8];          //    ID+version string
	DWORD hsize;         //    header size
	DWORD flag;          //    bitflag content information
	DWORD npatch;        //    number of patches
	BYTE minres;         //    min. resolution level
	BYTE maxres;         //    max. resolution level
};
#pragma pack(pop)


std::wstring string2wstring(const std::string& s);
std::string wstring2string(const std::wstring& s);

#endif
